package com.teckteam.ptvsystem.model;

import java.util.ArrayList;
import java.util.StringTokenizer;

/**
 * Generalised class to describe a stop. Abstract interaction may be useful
 * when implementing cross-transportation routes
 * 
 * -James
 */
public abstract class AbstractStop
{
   private String                   stopName, suburb;
   private ArrayList<DepartureTime> departureTimesList;
   private boolean                  isMajorStop;
   private ArrayList<AbstractStop>  connectingStops;
   private int stopCode;
   private Locality locality;
   private char transportType, directionFlag;
   
   /**
    * Common constructor for Stop object creation
    * 
    * @param timesList
    * @param stopName
    * @param dirFlag
    */
   public AbstractStop(String timesList[], String stopName, char dirFlag)
   {
      // TODO - Process departure times for instantiation
      /*
       * for(String s: times) System.err.println("DEBUG: "+s);
       */
      
      int hours = 0, minutes, prevHrs = 0, count = 0;
      boolean pastNoon = false, pastMidnight = false, isPm = false, isAm = false;
      String ampmThing[] = { "am", "pm" }, ampmPut = ampmThing[0], tmpName, tmpName2;
      
      // Break apart stop name prefix with first bracket indicating suburb
      String subSplit[] = stopName.split("[()]");
      this.stopName = subSplit[0];
      
      //Check if prefix is numeric as well as handling names with '-'
      String nameSplit[] = this.stopName.split("-");
      if(nameSplit.length!=1)
      {
         String filteredName;
         if(Character.isDigit(nameSplit[0].charAt(0)))
         {
            filteredName = nameSplit[1];
            
            if(nameSplit.length>2)
            {
               for(int i = 2; i < nameSplit.length; i++)
                  filteredName = filteredName.concat(nameSplit[i]);
            }
         } else
         {
            filteredName = nameSplit[0];
            for(int i = 1; i < nameSplit.length; i++)
               filteredName = filteredName.concat(nameSplit[i]);
         }
         
         filteredName = String.format("%s#%s ", filteredName, nameSplit[0]);
         this.stopName = filteredName;   
      }
      
      suburb = subSplit[subSplit.length-2];
      stopCode = Integer.parseInt(subSplit[subSplit.length-1].split("[|]")[1]);
      directionFlag = dirFlag;
      
      // Creating DepartureTime objects
      //loop through first to last, delimit | as express, - or " " as blank time
      departureTimesList = new ArrayList<DepartureTime>();
      DepartureTime blankTime = DepartureTime.getInstance();
      
      for (String s : timesList)
      {
         if (s.matches("\\d+[:]{1}\\d+"))
         {
            // Break apart string
            StringTokenizer st = new StringTokenizer(s, ":");
            
            hours = Integer.parseInt(st.nextToken());
            if (prevHrs != 0 && (hours == 12 || hours < 4 ) && hours > prevHrs && isAm == false
                  && isPm == false)
            {
               isPm = true;
               ampmPut = ampmThing[1];
            } else if (prevHrs != 0 && hours == 12 && hours > prevHrs
                  && isPm == true)
            {
               isAm = true;
               ampmPut = ampmThing[0];
            }
            minutes = Integer.parseInt(st.nextToken());
            
            DepartureTime d = DepartureTime.getInstance(hours, minutes, ampmPut);
            prevHrs = hours;
            departureTimesList.add(d);
         } else {
            //Construct blank time instance
            //DepartureTime d = new DepartureTime(s);
            //departureTimesList.add(d);
            departureTimesList.add(blankTime);
         }
         count++;
      }
      
   }
   
   /**
    * Return ArrayList of DepartureTime objects
    * @return
    */
   public ArrayList<DepartureTime> getDepartureTimes()
   {
      return departureTimesList;
   }
   
   /**
    * Return the parsed name of suburb
    * 
    * @return suburb
    */
   public String getSuburb()
   {
      //Falling back to hack parse in case Locality injection fails.
      if(locality==null)
         return suburb;
      
      return locality.getSuburb();
   }
   
   /**
    * Get DepartureTime object where  
    * @param hrs
    * @param mins
    * @param ampmFlag
    * @return
    */
   public DepartureTime getTime(int hrs, int mins, String ampmFlag)
   {
      //TODO
      return null;
   }
   
   public String toString()
   {
      return stopName;
   }
   
   public char getTransportType()
   {
      return transportType;
   }
   
   /**
    * Returns the direction flag of the stop object
    * @return directionFlag
    */
   public char getDirectionFlag()
   {
      return directionFlag;
   }
   
   /**
    * Return the parsed stopCode number (used for attaching GPS from csv list)
    * @return stopCode
    */
   public int getStopCode()
   {
      return stopCode;
   }
   
   /**
    * Return the locality object.  Null references should be handled outside.
    * @return locality
    */
   public Locality getLocality()
   {
      return locality;
   }
   
   /**
    * Insert Locality object instance (GPS coordinates)
    * 
    * @param locality
    */
   public void setLocality(Locality locality)
   {
      //if(this instanceof TramStop) - DEBUG checking injections for instances
      //System.err.printf("Locality appended for %s, %d\n", toString(), stopCode);
      this.locality = locality;
   }
   
   //Not actually used by anything but WalkingInstance
   protected void setTime(DepartureTime time)
   {
      //clear all times, then add new time
      departureTimesList.removeAll(departureTimesList);
      
      departureTimesList.add(time);
   }
   
   protected void setTransportType(char flag)
   {
      transportType = flag;
   }
   
   /**
    * Returns the next DepartureTime given a time string of format:
    *  "hh:mm [am/pm]"
    *  
    * @param time
    */
   public DepartureTime getNextDeparture(String time)
   {
      
      
      String timeSplit[] = time.split("[:-]");
      int hours = Integer.parseInt(timeSplit[0]),
          minutes = Integer.parseInt(timeSplit[1]);
      
      DepartureTime 
            inputTime = DepartureTime.getInstance(
                  hours, minutes, timeSplit[2]),
            outputTime = null;
      
      for(DepartureTime d : departureTimesList)
      {
         //Get the next departure time greater than or equal to input time.
         if(d.compareTo(inputTime)>=0)
         {
            outputTime = d;
         }
      }
      
      return outputTime;
   }
}
